package com.hejia.alauda.service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.springframework.stereotype.Service;

import com.hejia.alauda.entity.Presell;
import com.hejia.alauda.entity.Product;
import com.hejia.alauda.entity.Product.Category;
import com.hejia.alauda.entity.ProductEarningsRule;
import com.hejia.alauda.entity.example.PresellExample;
import com.hejia.alauda.exception.BusinessException;
import com.hejia.alauda.persistence.mybatis.PresellMapper;
import com.hejia.alauda.utils.Pager;

@Service
public class PresellServiceImpl implements PresellService {

	private static final Log Logger = LogFactory
			.getLog(PresellServiceImpl.class);

	@Resource
	private PresellMapper presellMapper;

	@Resource
	private ProductService productService;

	@Resource
	private WarningService warningService;

	@Resource
	private CalendarService calendarService;

	@Override
	public Pager<Presell> findAllPresell(Pager<Presell> pager) {
		return findAllPresell(pager, new PresellExample());
	}

	@Override
	public Pager<Presell> findAllPresell(Pager<Presell> pager,
			PresellExample example) {
		example.setOrderByClause("publish,createDate desc");
		pager.setList(presellMapper.selectByExample(example, pager));
		pager.setTotalCount(presellMapper.countByExample(example));
		return pager;
	}

	@Override
	public boolean savePresell(Presell presell) {

		presell.setCreateDate(new Date());
		presell.setModifyDate(new Date());
		presell.setPublish(false);

		if (presell.getRookie() == null) {
			presell.setRookie(false);
		}
		return presellMapper.insert(presell) > 0;
	}

	@Override
	public boolean modifyPresell(Presell presell) {
		return presellMapper.updateByPrimaryKey(presell) > 0;
	}

	@Override
	public Presell getPresellById(Long id) {
		return presellMapper.selectByPrimaryKey(id);
	}

	@Override
	public boolean deletePresell(Long id) {
		Presell presell = presellMapper.selectByPrimaryKey(id);
		return presellMapper.deleteByPrimaryKey(presell) > 0;
	}

	@Override
	public Presell getLastPresell(Product.Category category) {

		Pager<Presell> pager = new Pager<>();
		pager.setPageSize(1);

		PresellExample example = new PresellExample();
		example.appendCriterion("rookie =", 0);
		if (Product.Category.MONTH == category) {
			example.appendCriterion("type=", "月享");
			example.appendCriterion("publish=", false);
		} else if (Product.Category.QUARTER == category) {
			example.appendCriterion("type=", "季享");
			example.appendCriterion("publish=", false);
		} else {
			return null;
		}
		example.setOrderByClause("createDate asc");

		List<Presell> presells = presellMapper.selectByExample(example, pager);
		if (presells.size() > 0) {
			return presells.get(0);
		}
		return null;
	}

	@Override
	public Presell findLastPresell(Product.Category category) {

		Pager<Presell> pager = new Pager<>();
		pager.setPageSize(1);

		PresellExample example = new PresellExample();
		example.appendCriterion("rookie =", 0);
		example.appendCriterion("category =", category);
		example.setOrderByClause("createDate desc");
		List<Presell> presells = presellMapper.selectByExample(example, pager);

		if (presells.size() > 0) {
			return presells.get(0);
		}
		return null;
	}

	@Override
	public void publicRookiePresell() throws BusinessException {

		Logger.info("开始执行自动上架新手标产品");
		Integer rookieProductCount = this.productService
				.sumOnSellProductByCategoryAndAmount(null, true, 10000);
		if (rookieProductCount > 0) {
			return;
		}

		Product product = this.productService.findLastRookieProdutc();
		Presell presell = this.findNotPublicRookiePresell();
		if (presell == null) {
			Logger.info("无新手排期预售产品");
			this.warningService.sendNoneRookiePresellWarning();
		} else {
			publicRookiePresell(product, presell);
		}
	}

	/**
	 * 上架新手产品
	 * 
	 * @param product
	 *            最新新手产品
	 * @param presell
	 *            排期预售
	 * @throws BusinessException
	 */
	private void publicRookiePresell(Product product, Presell presell)
			throws BusinessException {

		DateTime now = new DateTime();

		Product newProduct = new Product();
		newProduct.setCategory(Product.Category.MONTH);

		// 设置产品名称
		String productname = product.getName().trim();
		String regEx = "[^0-9]";
		Pattern p = Pattern.compile(regEx);
		Matcher m = p.matcher(productname);
		Integer number = Integer.parseInt(m.replaceAll("")) + 1;

		String name = "欢乐合家 新手专享%s号";
		if (StringUtils.isNotEmpty(presell.getName())) {
			name = presell.getName();
		}
		newProduct.setName(String.format(name, number));

		if (presell.getTerm() == null) {
			newProduct.setTerm(7);
		} else {
			newProduct.setTerm(presell.getTerm());
		}

		newProduct.setInterestRate(new BigDecimal(0.050)); // 收益
		newProduct.setBonusRate(new BigDecimal(0.030)); // 平台赠送收益
		newProduct.setMinAmount(new BigDecimal(100.00)); // 起购金额
		newProduct.setMaxAmount(new BigDecimal(10000.00)); // 限购金额

		newProduct.setRiskLevel("R1"); // 风险等级
		newProduct.setRiskDescription("谨慎型 基本无风险"); // 风险描述
		newProduct.setRookie(true); // 是否新手标

		newProduct.setValueDate(now.toDate()); // 起息日
		newProduct.setStartTime(now.toDate()); // 起售时间
		DateTime endTime = now.plusDays(9);
		newProduct.setEndTime(new DateTime(endTime.getYear(), endTime
				.getMonthOfYear(), endTime.getDayOfMonth(), 23, 59).toDate()); // 结束时间

		newProduct.setFinancialAsset(presell.getFinancialAsset());
		newProduct.setTotalAmount(presell.getTotalAmount());
		newProduct.setType(presell.getProducttype());
		newProduct.setActivitys(presell.getActivitys());

		if (productService.saveProduct(newProduct)) {
			productService.publishProduct(newProduct.getSerial());
			presell.setPublish(true);
			this.modifyPresell(presell);
			Logger.info("保存产品成功");
		} else {
			Logger.info("保存产品失败");
		}
	}

	/**
	 * 查询未上架新手排期预售
	 * 
	 * @return
	 */
	private Presell findNotPublicRookiePresell() {

		Pager<Presell> pager = new Pager<>();
		pager.setPageSize(1);

		PresellExample example = new PresellExample();
		example.appendCriterion("rookie = 1");
		example.appendCriterion("publish = 0");
		example.setOrderByClause("createDate");
		List<Presell> presells = presellMapper.selectByExample(example, pager);

		if (presells.size() > 0) {
			return presells.get(0);
		}
		return null;
	}

	@Override
	public Presell findLastPresell(Category category, boolean rookie) {

		Pager<Presell> pager = new Pager<>();
		pager.setPageSize(1);

		PresellExample example = new PresellExample();
		if (category != null && Category.MONTH == category) {
			example.appendCriterion("type=", "月享");
		} else if (category != null && Category.QUARTER == category) {
			example.appendCriterion("type=", "季享");
		}

		example.appendCriterion("rookie =", rookie);
		example.setOrderByClause("createDate desc");
		List<Presell> presells = presellMapper.selectByExample(example, pager);

		if (presells.size() > 0) {
			return presells.get(0);
		}
		return null;
	}

	@Override
	public List<Presell> findNotPublicPresellsByFinancialAssetId(
			Long financialAssetId) {

		PresellExample example = new PresellExample();
		example.appendCriterion("publish=0");
		example.appendCriterion("financialAsset_id=", financialAssetId);

		return this.presellMapper.selectByExample(example, null);
	}

	@Override
	public void publicPresell(Category category) throws BusinessException {

		// 检查大于指定可售金额的在售产品数量
		Integer availableSellAmount = 50000;
		Integer onSellCount = this.productService
				.sumOnSellProductByCategoryAndAmount(category, false,
						availableSellAmount);
		if (onSellCount > 0) {
			return;
		}

		// 发布排期预售
		Presell presell = this.findNotPublicPresell(category);
		if (presell == null) {
			return;
		}
		if (presell.getPublish()) {
			return;
		}

		if (Category.CURRENT == category) {
			publicCurrentPresell(presell);
		} else if (Category.HALF_A_YEAR == category) {
			publicHalfAYearPresell(presell);
		} else if (Category.YEAR == category) {
			publicYearPresell(presell);
		} else if (Category.MONTH == category) {
			publicMonthPresell(presell);
		} else if (Category.QUARTER == category) {
			publicQuarterPresell(presell);
		} else {
			throw new RuntimeException("暂不支持自动上架此类别产品");
		}

	}

	private Presell findNotPublicPresell(Category category) {

		Pager<Presell> pager = new Pager<>();
		pager.setPageSize(1);

		PresellExample example = new PresellExample();
		example.appendCriterion("rookie =", 0);
		example.appendCriterion("publish =", 0);
		example.appendCriterion("category =", category);
		example.setOrderByClause("createDate");
		List<Presell> presells = presellMapper.selectByExample(example, pager);

		if (presells.size() > 0) {
			return presells.get(0);
		}
		return null;
	}

	/**
	 * 发布钱滚翻排期预售产品
	 * 
	 * @throws BusinessException
	 */
	private void publicCurrentPresell(Presell presell) throws BusinessException {

		DateTime now = new DateTime();

		Product product = new Product();
		product.setCategory(Product.Category.CURRENT);

		// 设置产品名称
		Integer number = this.productService.findMaxProductNumber(presell
				.getCategory()) + 1;
		String name = "欢乐合家 钱滚翻%s号";
		if (StringUtils.isNotEmpty(presell.getName())) {
			name = presell.getName();
		}
		product.setName(String.format(name, number));

		product.setBonusRate(new BigDecimal(0.005)); // 平台赠送收益
		product.setMinAmount(new BigDecimal(1000.00)); // 起购金额
		product.setMaxAmount(new BigDecimal(500000.00)); // 限购金额

		product.setRiskLevel("R1"); // 风险等级
		product.setRiskDescription("谨慎型 基本无风险"); // 风险描述
		product.setRookie(false); // 是否新手标

		product.setValueDate(now.toDate()); // 起息日
		product.setStartTime(now.toDate()); // 起售时间
		product.setEndTime(new DateTime(now.getYear(), now.getMonthOfYear(),
				now.getDayOfMonth(), 23, 59).toDate()); // 结束时间，钱滚翻不能跨天卖

		product.setFinancialAsset(presell.getFinancialAsset());
		product.setTotalAmount(presell.getTotalAmount());
		product.setType(presell.getProducttype());
		product.setActivitys(presell.getActivitys());

		// 添加收益规则
		addProductEarningsRule(product, 30, 0.067);
		addProductEarningsRule(product, 60, 0.073);
		addProductEarningsRule(product, 90, 0.079);
		addProductEarningsRule(product, 120, 0.085);
		addProductEarningsRule(product, 150, 0.091);
		addProductEarningsRule(product, 180, 0.097);

		if (productService.saveProduct(product)) {
			productService.publishProduct(product.getSerial());
			presell.setPublish(true);
			this.modifyPresell(presell);
			Logger.info("保存产品成功");
		} else {
			Logger.info("保存产品失败");
		}

	}

	/**
	 * 发布双季汇排期预售产品
	 * 
	 * @throws BusinessException
	 */
	private void publicHalfAYearPresell(Presell presell)
			throws BusinessException {

		DateTime now = new DateTime();

		Product product = new Product();
		product.setCategory(Product.Category.HALF_A_YEAR);

		// 设置产品名称
		Integer number = this.productService.findMaxProductNumber(presell
				.getCategory()) + 1;
		String name = "欢乐合家 双季汇%s号";
		if (StringUtils.isNotEmpty(presell.getName())) {
			name = presell.getName();
		}
		product.setName(String.format(name, number));

		product.setBonusRate(new BigDecimal(0.01)); // 平台赠送收益
		product.setMinAmount(new BigDecimal(1000.00)); // 起购金额
		product.setMaxAmount(new BigDecimal(500000.00)); // 限购金额

		product.setRiskLevel("R1"); // 风险等级
		product.setRiskDescription("谨慎型 基本无风险"); // 风险描述
		product.setRookie(false); // 是否新手标

		product.setValueDate(now.toDate()); // 起息日
		product.setStartTime(now.toDate()); // 起售时间
		product.setEndTime(new DateTime(now.getYear(), now.getMonthOfYear(),
				now.getDayOfMonth(), 23, 59).toDate()); // 结束时间，钱滚翻不能跨天卖

		product.setFinancialAsset(presell.getFinancialAsset());
		product.setTotalAmount(presell.getTotalAmount());
		product.setType(presell.getProducttype());
		product.setActivitys(presell.getActivitys());
		product.setInterestRate(new BigDecimal(0.1));

		int termParam = 180;
		if (presell.getTerm() != null) {
			termParam = presell.getTerm();
		}

		int term = this.adjustTermAvoidHolidayRepay(product.getStartTime(),
				product.getEndTime(), termParam, 10);
		product.setTerm(term);

		if (productService.saveProduct(product)) {
			productService.publishProduct(product.getSerial());
			presell.setPublish(true);
			this.modifyPresell(presell);
			Logger.info("保存产品成功");
		} else {
			Logger.info("保存产品失败");
		}

	}

	/**
	 * 发布年享排期预售产品
	 * 
	 * @throws BusinessException
	 */
	private void publicYearPresell(Presell presell) throws BusinessException {

		DateTime now = new DateTime();

		Product product = new Product();
		product.setCategory(Product.Category.YEAR);

		// 设置产品名称
		Integer number = this.productService.findMaxProductNumber(presell
				.getCategory()) + 1;
		String name = "欢乐合家 年享%s号";
		if (StringUtils.isNotEmpty(presell.getName())) {
			name = presell.getName();
		}
		product.setName(String.format(name, number));

		product.setBonusRate(new BigDecimal(0.01)); // 平台赠送收益
		product.setMinAmount(new BigDecimal(1000.00)); // 起购金额
		product.setMaxAmount(new BigDecimal(500000.00)); // 限购金额

		product.setRiskLevel("R1"); // 风险等级
		product.setRiskDescription("谨慎型 基本无风险"); // 风险描述
		product.setRookie(false); // 是否新手标

		product.setValueDate(now.toDate()); // 起息日
		product.setStartTime(now.toDate()); // 起售时间
		product.setEndTime(new DateTime(now.getYear(), now.getMonthOfYear(),
				now.getDayOfMonth(), 23, 59).toDate()); // 结束时间，钱滚翻不能跨天卖

		product.setFinancialAsset(presell.getFinancialAsset());
		product.setTotalAmount(presell.getTotalAmount());
		product.setType(presell.getProducttype());
		product.setActivitys(presell.getActivitys());
		product.setInterestRate(new BigDecimal(0.11));

		int termParam = 0;
		if (presell.getTerm() != null) {
			termParam = presell.getTerm();
		}

		int term = this.adjustTermAvoidHolidayRepay(product.getStartTime(),
				product.getEndTime(), termParam, 10);
		product.setTerm(term);

		if (productService.saveProduct(product)) {
			productService.publishProduct(product.getSerial());
			presell.setPublish(true);
			this.modifyPresell(presell);
			Logger.info("保存产品成功");
		} else {
			Logger.info("保存产品失败");
		}

	}

	/**
	 * 发布月享排期预售产品
	 * 
	 * @throws BusinessException
	 */
	private void publicMonthPresell(Presell presell) throws BusinessException {

		DateTime now = new DateTime();

		Product product = new Product();
		product.setCategory(Product.Category.MONTH);

		// 设置产品名称
		Integer number = this.productService.findMaxProductNumber(presell
				.getCategory()) + 1;
		String name = "欢乐合家 月享%s号";
		if (StringUtils.isNotEmpty(presell.getName())) {
			name = presell.getName();
		}
		product.setName(String.format(name, number));

		product.setBonusRate(new BigDecimal(0.01)); // 平台赠送收益
		product.setMinAmount(new BigDecimal(500.00)); // 起购金额
		product.setMaxAmount(new BigDecimal(500000.00)); // 限购金额

		product.setRiskLevel("R1"); // 风险等级
		product.setRiskDescription("谨慎型 基本无风险"); // 风险描述
		product.setRookie(false); // 是否新手标

		product.setValueDate(now.toDate()); // 起息日
		product.setStartTime(now.toDate()); // 起售时间
		product.setEndTime(new DateTime(now.getYear(), now.getMonthOfYear(),
				now.getDayOfMonth(), 23, 59).toDate()); // 结束时间，钱滚翻不能跨天卖

		product.setFinancialAsset(presell.getFinancialAsset());
		product.setTotalAmount(presell.getTotalAmount());
		product.setType(presell.getProducttype());
		product.setActivitys(presell.getActivitys());
		product.setInterestRate(new BigDecimal(0.07));

		int termParam = 30;
		if (presell.getTerm() != null) {
			termParam = presell.getTerm();
		}

		int term = this.adjustTermAvoidHolidayRepay(product.getStartTime(),
				product.getEndTime(), termParam, 10);
		product.setTerm(term);

		if (productService.saveProduct(product)) {
			productService.publishProduct(product.getSerial());
			presell.setPublish(true);
			this.modifyPresell(presell);
			Logger.info("保存产品成功");
		} else {
			Logger.info("保存产品失败");
		}

	}

	/**
	 * 发布季享排期预售产品
	 * 
	 * @throws BusinessException
	 */
	private void publicQuarterPresell(Presell presell) throws BusinessException {

		DateTime now = new DateTime();

		Product product = new Product();
		product.setCategory(Product.Category.QUARTER);

		// 设置产品名称
		Integer number = this.productService.findMaxProductNumber(presell
				.getCategory()) + 1;
		String name = "欢乐合家 季享%s号";
		if (StringUtils.isNotEmpty(presell.getName())) {
			name = presell.getName();
		}
		product.setName(String.format(name, number));

		product.setBonusRate(new BigDecimal(0.01)); // 平台赠送收益
		product.setMinAmount(new BigDecimal(1000.00)); // 起购金额
		product.setMaxAmount(new BigDecimal(500000.00)); // 限购金额

		product.setRiskLevel("R1"); // 风险等级
		product.setRiskDescription("谨慎型 基本无风险"); // 风险描述
		product.setRookie(false); // 是否新手标

		product.setValueDate(now.toDate()); // 起息日
		product.setStartTime(now.toDate()); // 起售时间
		product.setEndTime(new DateTime(now.getYear(), now.getMonthOfYear(),
				now.getDayOfMonth(), 23, 59).toDate()); // 结束时间，钱滚翻不能跨天卖

		product.setFinancialAsset(presell.getFinancialAsset());
		product.setTotalAmount(presell.getTotalAmount());
		product.setType(presell.getProducttype());
		product.setActivitys(presell.getActivitys());
		product.setInterestRate(new BigDecimal(0.08));

		int termParam = 90;
		if (presell.getTerm() != null) {
			termParam = presell.getTerm();
		}

		int term = this.adjustTermAvoidHolidayRepay(product.getStartTime(),
				product.getEndTime(), termParam, 10);
		product.setTerm(term);

		if (productService.saveProduct(product)) {
			productService.publishProduct(product.getSerial());
			presell.setPublish(true);
			this.modifyPresell(presell);
			Logger.info("保存产品成功");
		} else {
			Logger.info("保存产品失败");
		}

	}

	/**
	 * 添加产品收益规则
	 * 
	 * @param product
	 *            产品
	 * @param holdingTime
	 *            持有时间
	 * @param interestRate
	 *            年化利率
	 */
	private void addProductEarningsRule(Product product, int holdingTime,
			double interestRate) {

		ProductEarningsRule rule = new ProductEarningsRule();
		rule.setProduct(product);
		rule.setInterestRate(BigDecimal.valueOf(interestRate));

		int term = this.adjustTermAvoidHolidayRepay(product.getStartTime(),
				product.getEndTime(), holdingTime, 10);
		rule.setHoldingTime(term);

		product.getEarningsRules().add(rule);
	}

	@Override
	public int adjustTermAvoidHolidayRepay(Date startTime, Date endTime,
			int term, int maxAdjustDays) {

		LocalDate start = new DateTime(startTime).toLocalDate();
		LocalDate end = new DateTime(endTime).toLocalDate();

		// 计算区间天数
		Period period = new Period(start, end, PeriodType.days());
		int days = period.getDays();

		for (int adjustDays = 0; adjustDays <= maxAdjustDays; adjustDays++) {
			boolean isInHoliday = false;
			for (int day = 0; day <= days; day++) {
				LocalDate date = start.plusDays(day);
				if (this.calendarService.isHoliday(date.plusDays(
						term + adjustDays).toDate())) {
					isInHoliday = true;
					break;
				}
			}
			if (!isInHoliday) {
				return term + adjustDays;
			}
		}

		throw new RuntimeException("最大调整天数内没有找到没有落到节假日兑付的产品期限");
	}

}
